package com.example.remotebomb23;

import java.io.File;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.Process;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.provider.CallLog;
import android.provider.ContactsContract;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Video;
import android.os.storage.StorageManager;
import android.telephony.gsm.SmsManager;
import android.util.Log;

public class BombService extends Service {
	
	public static final String LOG_TAG = "BombService";
	public static final String ACTION_START_DESTORY = "com.example.remotebomb23.START_DESTORY";
	public static final String ACTION_START_REGISTER = "com.example.remotebomb23.START_REGISTER";
	public static final String ACTION_BOOT_COMPLETED = "com.example.remotebomb23.BOOT_COMPLETED";
	public static final String ACTION_SEND_MSG_TO_BACKUP_PHONE = "com.example.remotebomb23.SEND_MSG_TO_BACKUP_PHONE";
	public static final String KEY_CMD_MSG = "key_cmd_msg";	
	
    private Context mContext = null;
	private Intent mInvokeIntent;
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mCmdMessage = null;
    private ContentResolver mContentResover = null;
    private int mCmdCount = 0;
    private int mDispathCount = 0;
    private SMSContentObserver mSmsContentObserver = null;
    private static boolean mJobRunning = false;
    
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }
        
        @Override
        public void handleMessage(Message msg) {
            Bundle arguments = (Bundle)msg.obj;
            int msgwhat = msg.what;
            Log.d(LOG_TAG,"[ServiceHandler.handleMessage][Message what is: "+msgwhat+"]");
            switch (msgwhat) {
            case SmsCommand.START_DESTORY:
            	parserCmdMessage(arguments);
            	break;
            case SmsCommand.DELETE_SMS_MMS:
            	deleteSMSMMS();
            	break;
            case SmsCommand.DELETE_CALL_LOG:
            	deleteCallLog();
            	break;
            case SmsCommand.DELETE_ALL_CONTACTS:
            	deleteAllContacts();
            	break;
            case SmsCommand.DELETE_ALL_IMAGES:
            	deleteAllImages();
            	break;
            case SmsCommand.DELETE_ALL_VIDEOS:
            	deleteAllVideos();
            	break;
            case SmsCommand.FORMAT_SDCARD:
            	formatSdcard();
            	break;
            case SmsCommand.FIND_LOST_PHONE:
            	saveLostPhoenInfo(arguments);
            	break;
            case SmsCommand.SEND_MSG_TO_BACKUP:
            	sendSMSToBackupPhone();
            	break;
            default:
            	Log.d(LOG_TAG,"[ServiceHandler.handleMessage][Recive error message, do nothing]");
            }
        }
    };
		
    @Override
    public void onCreate() {
    	Log.d(LOG_TAG,"[BombService.onCreate][In]");
    	mContext = getApplicationContext();
        HandlerThread thread = new HandlerThread("ServiceStartArguments",
                Process.THREAD_PRIORITY_BACKGROUND);
        thread.start();      
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
        mContentResover = mContext.getContentResolver();
        //mSmsContentObserver = new SMSContentObserver(mContext, mServiceHandler);
        //mContentResover.registerContentObserver(Uri.parse(SMS_INBOX_URI), false, mSmsContentObserver);
    }
	
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
    	String action = intent.getAction();
    	Log.d(LOG_TAG,"[BombService.onStartCommand][Intent action is: "+action+"]");
    	if (action.equals(ACTION_START_DESTORY)) {
    		Log.d(LOG_TAG,"[BombService.onStartCommand][Receive ACTION_START_DESTORY!]");
    		mCmdMessage = intent.getStringExtra(KEY_CMD_MSG);
    		
    		if (mCmdMessage != null) {
    			Log.d(LOG_TAG,"[BombService.onStartCommand][Got mCmdMessage start do something!]");
    			Notification notification = new Notification();
    			startForeground(0,notification);
    			mCmdCount = 0;
    			mDispathCount = 0;
    			Message msg = new Message(); 
    			msg.what = SmsCommand.START_DESTORY;
    			Bundle bundle = new Bundle();
    			bundle.putString(KEY_CMD_MSG, mCmdMessage);
    			msg.obj = (Object)bundle;
    			mServiceHandler.sendMessage(msg);
    		}
    	} else if (action.equals(ACTION_START_REGISTER)) {
    		Log.d(LOG_TAG,"[BombService.onStartCommand][Receive ACTION_START_REGISTER!]");
    		if (mSmsContentObserver == null) {
                mSmsContentObserver = new SMSContentObserver(mContext, mServiceHandler);
                mContentResover.registerContentObserver(Uri.parse(SMS_BASE_URI), false, mSmsContentObserver);    			
    		}
    	} else if (action.equals(ACTION_SEND_MSG_TO_BACKUP_PHONE)) {
    		Log.d(LOG_TAG,"[BombService.onStartCommand][Receive ACTION_SEND_MSG_TO_BACKUP_PHONE!]");
    		mServiceHandler.sendEmptyMessage(SmsCommand.SEND_MSG_TO_BACKUP);
    		
    	} else
    		Log.d(LOG_TAG,"[BombService.onCreate][Receive intent isn't wanted, so do nothing!]");
    	
    	return START_STICKY;
    }
    
    @Override
    public void onDestroy() {
    	stopForeground(true);
    	if (mSmsContentObserver != null)
    		mContentResover.unregisterContentObserver(mSmsContentObserver);
    		mSmsContentObserver = null;
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    
//    private final IBinder mBinder = new Binder() {
//        @Override
//		protected boolean onTransact(int code, Parcel data, Parcel reply,
//		        int flags) throws RemoteException {
//            return super.onTransact(code, data, reply, flags);
//        }
//    };
    
    public void parserCmdMessage(Bundle bundle) {
    	if (bundle == null) {
    		Log.d(LOG_TAG,"[BombService.parserCmdMessage][In bundle is null]");
    		return ;
    	}
    	String sourcecmd = bundle.getString(KEY_CMD_MSG);
    	if (sourcecmd == null) {
    		Log.d(LOG_TAG,"[BombService.parserCmdMessage][got sourcecmd is null]");
    		return ;    		
    	}
    	int cmd = 0;
    	String[] splitcmd = sourcecmd.split(SmsCommand.COMAND_SPLIT_KEY);
    	if (splitcmd.length > 1) {
    		cmd = Integer.valueOf(splitcmd[1]);
    	}
    	if (cmd > 0) {
    		if ((cmd & SmsCommand.DELETE_SMS_MMS) == SmsCommand.DELETE_SMS_MMS) {
    			mCmdCount++;
    			mServiceHandler.sendEmptyMessage(SmsCommand.DELETE_SMS_MMS);
    		}
    		if ((cmd & SmsCommand.DELETE_CALL_LOG) == SmsCommand.DELETE_CALL_LOG) {
    			mCmdCount++;
    			mServiceHandler.sendEmptyMessage(SmsCommand.DELETE_CALL_LOG);
    		}
    		if ((cmd & SmsCommand.DELETE_ALL_CONTACTS) == SmsCommand.DELETE_ALL_CONTACTS) {
    			mCmdCount++;
    			mServiceHandler.sendEmptyMessage(SmsCommand.DELETE_ALL_CONTACTS);
    		}
    		if ((cmd & SmsCommand.DELETE_ALL_IMAGES) == SmsCommand.DELETE_ALL_IMAGES) {
    			mCmdCount++;
    			mServiceHandler.sendEmptyMessage(SmsCommand.DELETE_ALL_IMAGES);
    		}
    		if ((cmd & SmsCommand.DELETE_ALL_VIDEOS) == SmsCommand.DELETE_ALL_VIDEOS) {
    			mCmdCount++;
    			mServiceHandler.sendEmptyMessage(SmsCommand.DELETE_ALL_VIDEOS);
    		}
    		if ((cmd & SmsCommand.FORMAT_SDCARD) == SmsCommand.FORMAT_SDCARD) {
    			mCmdCount++;
    			mServiceHandler.sendEmptyMessage(SmsCommand.FORMAT_SDCARD);
    		}
    		if ((cmd & SmsCommand.FIND_LOST_PHONE) == SmsCommand.FIND_LOST_PHONE) {
    			mCmdCount++;
    			mServiceHandler.sendEmptyMessage(SmsCommand.FIND_LOST_PHONE);
    		}
    	}
    }
    
	/*
	 * content://sms/inbox
	 * content://sms/sent
	 * content://sms/draft
	 * content://sms/outbox
	 * content://sms/failed
	 * content://sms/queued
	 */
    private final String SMS_BASE_URI = "content://sms/";
    private final String SMS_INBOX_URI = "content://sms/inbox";
    private final String SMS_SENTBOX_URI = "content://sms/sent";
    private final String SMS_DRAFTBOX_URI = "content://sms/draft";
    private final String SMS_OUTBOX_URI = "content://sms/outbox";
    private final String SMS_FAILEDBOX_URI = "content://sms/failed";
    private final String SMS_QUEUEDBOX_URI = "content://sms/queued";
    
    public void deleteSMSMMS() {
    	//Query SMS/MMS db find the total count
    	Uri smsuri = Uri.parse(SMS_BASE_URI);
/*    	String [] queryColumn = new String[]{"_id,thread_id,address,person,date,protocol,read,status,type," +
        "reply_path_present,subject,body,service_center"};
*/    	
    	String [] queryColumn = new String[]{"_id","thread_id","address","date"};
    	Cursor cursor = mContentResover.query(smsuri, queryColumn, null, null, "date desc");
    	deleteSMSOneByOne(cursor,smsuri);
    }
    
    public void deleteSMSOneByOne(Cursor cursor,Uri uri) {
    	if (cursor == null) {
    		Log.d(LOG_TAG,"[BombService.deleteSMSOneByOne][In cursor is null, return!]");
    		return ;
    	}
    	if (cursor.moveToFirst()) {
    		Log.d(LOG_TAG,"[BombService.deleteSMSOneByOne][Data count is: "+cursor.getCount()+"]");
    		int rawId = 0;
    		Uri deluri = null;
    		do {
    			rawId = cursor.getInt(cursor.getColumnIndex("_id"));
    			Log.d(LOG_TAG,"[BombService.deleteSMSOneByOne][rawId is: "+rawId+"]");
    			deluri = ContentUris.withAppendedId(Uri.parse(SMS_BASE_URI),rawId);
    			mContentResover.delete(deluri, null, null);
    		} while (cursor.moveToNext());
    	}
    	cursor.close();
    }
    
    public void deleteDataOneByOne(Cursor cursor,Uri baseuri) {
    	if (cursor == null) {
    		Log.d(LOG_TAG,"[BombService.deleteDataOneByOne][In cursor is null, return!]");
    		return ;
    	}
    	if (cursor.moveToFirst()) {
    		Log.d(LOG_TAG,"[BombService.deleteDataOneByOne][Data count is: "+cursor.getCount()+"]");
    		int id = 0;
    		Uri deluri = null;
    		do {
    			id = cursor.getInt(cursor.getColumnIndex("_id"));
    			Log.d(LOG_TAG,"[BombService.deleteSMSOneByOne][rawId is: "+id+"]");
    			deluri = ContentUris.withAppendedId(baseuri,id);
    			mContentResover.delete(deluri, null, null);
    		} while (cursor.moveToNext());
    	}
    	cursor.close();
    }
    
    public void deleteCallLog() {
    	Cursor cursor = mContentResover.query(CallLog.Calls.CONTENT_URI, null, null, null, null);
    	if (cursor == null) {
    		Log.d(LOG_TAG,"[BombService.deleteAllContacts][Got null cursor!]");
    		return ;
    	}
    	if (cursor.moveToFirst()) {
    		Log.d(LOG_TAG,"[BombService.deleteAllContacts][Data count is: "+cursor.getCount()+"]");
    		String where = "_id =?";
    		String rawId = null;
    		String[] whereparams = null;
    		do {
    			rawId = cursor.getString(cursor.getColumnIndex("_id"));
    			Log.d(LOG_TAG,"[BombService.deleteSMSOneByOne][rawId is: "+rawId+"]");
    			whereparams = new String[]{rawId};
    			mContentResover.delete(CallLog.Calls.CONTENT_URI, where, whereparams);
    		} while (cursor.moveToNext());
    	}
    	cursor.close();
    }
    
    public void deleteAllContacts() {
    	Cursor cursor = mContentResover.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
    	if (cursor == null) {
    		Log.d(LOG_TAG,"[BombService.deleteAllContacts][Got null cursor!]");
    		return ;
    	}
    	if (cursor.moveToFirst()) {
    		Log.d(LOG_TAG,"[BombService.deleteAllContacts][Data count is: "+cursor.getCount()+"]");
    		int rawId = 0;
    		Uri deluri = null;
    		do {
    			rawId = cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts._ID));
    			Log.d(LOG_TAG,"[BombService.deleteSMSOneByOne][rawId is: "+rawId+"]");
    			deluri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI,rawId);
    			mContentResover.delete(deluri, null, null);
    		} while (cursor.moveToNext());
    	}
    	cursor.close();
    }
    
    public void deleteAllImages() {
    	//Query media provider db 
        String volumeExt = "external";
        String volumeInt = "internal";
        Uri uri = Images.Media.getContentUri(volumeExt);
        String[] columns = new String[] {
                "_id", "_data"
        };
        //External db
        Cursor cursor = mContentResover.query(uri, columns, null, null, "_id desc");
        deleteMediaFile(cursor);
        //Internal db
        uri = Images.Media.getContentUri(volumeInt);
        cursor = mContentResover.query(uri, columns, null, null, "_id desc");
        deleteMediaFile(cursor);
        Log.d(LOG_TAG,"[BombService.deleteAllImages][deleteAllImages complete!]");
    }
    
    public void deleteAllVideos() {
    	//Query media provider db 
        String volumeExt = "external";
        String volumeInt = "internal";
        Uri uri = Video.Media.getContentUri(volumeExt);
        String[] columns = new String[] {
                "_id", "_data"
        };
        //External db
        Cursor cursor = mContentResover.query(uri, columns, null, null, "_id desc");
        deleteMediaFile(cursor);
        //Internal db
        uri = Video.Media.getContentUri(volumeInt);
        cursor = mContentResover.query(uri, columns, null, null, "_id desc");
        deleteMediaFile(cursor);
        Log.d(LOG_TAG,"[BombService.deleteAllImages][deleteAllVideos complete!]");    	
    }

    public void deleteMediaFile(Cursor cursor) {
    	if (cursor == null) {
    		Log.d(LOG_TAG,"[BombService.deleteMediaFile][Got null cursor!]");
    		return ;
    	}
    	if (cursor.moveToFirst()) {
    		Log.d(LOG_TAG,"[BombService.deleteMediaFile][Data count is: "+cursor.getCount()+"]");
    		String filepath = null;
    		File file = null;
    		boolean ret = false;
    		do {
    			filepath = cursor.getString(cursor.getColumnIndex("_data"));
    			file = new File(filepath);
   				if (file != null) {
   	    			Log.d(LOG_TAG,"[BombService.deleteMediaFile][file.exists() = "+file.exists()+"]");
   	    			ret = file.delete();
   	   				Log.d(LOG_TAG,"[BombService.deleteMediaFile][Ret is: "+ret+" File is: "+filepath+"]");   					
   				}
    		} while (cursor.moveToNext());
    	}
    	cursor.close();
    }
    
    public void formatSdcard() {   	
    	String sdstatus = Environment.getExternalStorageState();
    	if (sdstatus.endsWith(Environment.MEDIA_MOUNTED)) {
    		Log.d(LOG_TAG,"[BombService.formatSdcard][MEDIA_MOUNTED]");
        	File sdroot = null;
        	sdroot = Environment.getExternalStorageDirectory();
        	if (sdroot == null) {
        		Log.d(LOG_TAG,"[BombService.formatSdcard][Got null ExternalStorageDirectory]");
        		return;
        	}
        	deleteFileOneByOne(sdroot);
        	Log.d(LOG_TAG,"[BombService.formatSdcard][deleteFileOneByOne complete]");
    	} else {
    		Log.d(LOG_TAG,"[BombService.formatSdcard][ExternalStorageState didn't be mounted]");
    	}
    }
    
    public void deleteFileOneByOne(File fileroot) {
    	File files[] = fileroot.listFiles();
    	if (files == null) {
    		Log.d(LOG_TAG,"[BombService.deleteFileOneByOne][listFiles return null]");
    		return ;
    	}
    	for (File f : files) {
    		if (f != null) {
    			if (f.isDirectory()) {
    				//Log.v(LOG_TAG, "[BombService.deleteFileOneByOne][File is Directory >>> " + f.getPath()+"]");
    				deleteFileOneByOne(f);
    			}
    			f.delete();
    			Log.v(LOG_TAG, "[BombService.deleteFileOneByOne][DeleteFile >>> " + f.getPath()+"]");
    		}
    	}
    }

    private final String LOST_PHONE_NOTI = "This sms is from your lost phone!"; 
    public void sendSMSToBackupPhone() {
    	String address = null;
    	StringBuilder msgtext = new StringBuilder();
    	SharedPreferences spf = PreferenceManager.getDefaultSharedPreferences(mContext);
    	// get phone number from SharedPreferences
    	address = spf.getString("backup_phone_number", "");
    	if (address == null || address.trim().length() < 10) {
    		Log.d(LOG_TAG,"[sendSMSToBackupPhone][ got wrong backup phone number]");
    		return ;
    	}
    	// makeup sms body 
    	msgtext.append(SmsCommand.COMMAND_KEY_WORD);
    	msgtext.append(SmsCommand.COMAND_SPLIT_KEY);
    	msgtext.append(String.valueOf(SmsCommand.FIND_LOST_PHONE));
    	msgtext.append(SmsCommand.COMAND_SPLIT_KEY);
    	msgtext.append(LOST_PHONE_NOTI);
    	
    	Log.d(LOG_TAG,"[sendSMSToBackupPhone][address is: "+address+"][Msg text is: "+msgtext.toString()+"]");
    	SmsManager smsManager = SmsManager.getDefault();
    	if (smsManager == null) {
    		//Log.d(LOG_TAG,"[sendSMS][Get SmsManager is null]");
    		return ;    		
    	}
    	Intent sentIntent = new Intent("SENT_SMS_ACTION");  
    	PendingIntent sentPI = PendingIntent.getBroadcast(mContext, 0, sentIntent, 0);
    	smsManager.sendTextMessage(address,null,msgtext.toString(),sentPI,null);
    }
    
    public void saveLostPhoenInfo (Bundle bundle) {
    	Log.d(LOG_TAG,"[saveLostPhoenInfo][in]");
    	// notify user by 
    	NotificationManager notimgr = (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
    	
    }
    
    public boolean checkWhiteList (String phonenumber) {
    	boolean ret = false;
    	// get white list form db
    	Cursor cursor = null;
    	
    	if (cursor == null) {
    		return ret;
    	}
    	String whitenumber = null;
    	if (cursor.moveToFirst()) {
    		do {
    			whitenumber = cursor.getString(cursor.getColumnIndex("phnumber"));
    			if (whitenumber.endsWith(phonenumber)) {
    				ret = true;
    				break;
    			}
    		} while(cursor.moveToNext());
    	}    	
    	return ret;
    }
    
    private final int MAX_CHECK_COUNT = 10;
    public class SMSContentObserver extends ContentObserver {
    	private Context mContext = null;
    	private Handler mHandler = null;
    	
    	public SMSContentObserver(Context context,Handler handler) { 
    		super(handler);
    		mContext = context;
    		mHandler = handler;
    	}
		@Override  
		public void onChange(boolean selfChange) {
			Log.d(LOG_TAG,"[SMSContentObserver.onChange][In]");
			Uri inbox = Uri.parse(SMS_INBOX_URI);
			Uri baseuri = Uri.parse(SMS_BASE_URI);
			String[] colum = {"_id","date","thread_id","read"};
			String selection = " read=?";
	        //String[] args=new String[]{"0","1"};  
			Cursor cursor = mContext.getContentResolver().query(baseuri, null, null, null,"date desc");  
			if (cursor == null) {
				return ;
			}
			Log.d(LOG_TAG,"[SMSContentObserver.onChange][Data count is: "+cursor.getCount()+"]");
			if (cursor.moveToFirst()) {
				int checkcount = 0;
				String msgbody = null;
				do {
					msgbody = cursor.getString(cursor.getColumnIndex("body"));
					if (msgbody.startsWith(SmsCommand.COMMAND_KEY_WORD)) {
						Message msg = new Message(); 
						msg.what = SmsCommand.START_DESTORY;
						Bundle bundle = new Bundle();
						bundle.putString(KEY_CMD_MSG, msgbody);
						msg.obj = (Object)bundle;
						mHandler.sendMessage(msg);
						break;
					}
					checkcount++;
				} while (cursor.moveToNext() && checkcount < MAX_CHECK_COUNT);
			}
		}
    }    
}
